﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Com.Lancetinc.Evs.Controls;

namespace Com.Lancetinc.Evs
{
    public class NeoCard : ContentControl
    {
        static NeoCard()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NeoCard), new FrameworkPropertyMetadata(typeof(NeoCard)));
        }

        private static void UpdateShaderPropSafe(DependencyObject d, Action<NeoShader> action)
        {
            if (d is NeoCard { _shader: { } } neoCard)
            {
                action(neoCard._shader);
            }
        }

        #region OffsetX
        public double OffsetX
        {
            get => (double)GetValue(OffsetXProperty);
            set => SetValue(OffsetXProperty, value);
        }

        public static readonly DependencyProperty OffsetXProperty =
            DependencyProperty.Register(nameof(OffsetX), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(7.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.OffsetX = (double)e.NewValue);
                })
            );

        #endregion

        #region OffsetY
        public double OffsetY
        {
            get => (double)GetValue(OffsetYProperty);
            set => SetValue(OffsetYProperty, value);
        }

        public static readonly DependencyProperty OffsetYProperty =
            DependencyProperty.Register(nameof(OffsetY), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(5.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.OffsetY = (double)e.NewValue);
                })
            );

        #endregion

        #region BlurRadius
        public double BlurRadius
        {
            get => (double)GetValue(BlurRadiusProperty);
            set => SetValue(BlurRadiusProperty, value);
        }

        public static readonly DependencyProperty BlurRadiusProperty =
            DependencyProperty.Register(nameof(BlurRadius), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(5.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.BlurRadius = (double)e.NewValue);
                })
            );

        #endregion

        #region SpreadRadius
        public double SpreadRadius
        {
            get => (double)GetValue(SpreadRadiusProperty);
            set => SetValue(SpreadRadiusProperty, value);
        }

        public static readonly DependencyProperty SpreadRadiusProperty =
            DependencyProperty.Register(nameof(SpreadRadius), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(2.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.SpreadRadius = (double)e.NewValue);
                })
            );

        #endregion

        #region BorderRadius
        public double BorderRadius
        {
            get => (double)GetValue(BorderRadiusProperty);
            set => SetValue(BorderRadiusProperty, value);
        }

        public static readonly DependencyProperty BorderRadiusProperty =
            DependencyProperty.Register(nameof(BorderRadius), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(0.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.BorderRadius = (double)e.NewValue);
                })
            );

        #endregion

        #region PrimaryColor
        public Color PrimaryColor
        {
            get => (Color)GetValue(PrimaryColorProperty);
            set => SetValue(PrimaryColorProperty, value);
        }

        public static readonly DependencyProperty PrimaryColorProperty =
            DependencyProperty.Register(nameof(PrimaryColor), typeof(Color), typeof(NeoCard),
                new UIPropertyMetadata(Colors.Silver, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.PrimaryColor = (Color)e.NewValue);
                })
            );

        #endregion

        #region SecondaryColor
        public Color SecondaryColor
        {
            get => (Color)GetValue(SecondaryColorProperty);
            set => SetValue(SecondaryColorProperty, value);
        }

        public static readonly DependencyProperty SecondaryColorProperty =
            DependencyProperty.Register(nameof(SecondaryColor), typeof(Color), typeof(NeoCard),
                new UIPropertyMetadata(Colors.WhiteSmoke, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.SecondaryColor = (Color)e.NewValue);
                })
            );

        #endregion

        #region Inset
        /// <summary>
        /// 0：凸出
        /// 2：凹进
        /// </summary>
        public double Inset
        {
            get => (double)GetValue(InsetProperty);
            set => SetValue(InsetProperty, value);
        }

        public static readonly DependencyProperty InsetProperty =
            DependencyProperty.Register(nameof(Inset), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(0.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.Inset = (double)e.NewValue);
                })
            );

        #endregion

        #region RenderingMode
        public double RenderingMode
        {
            get => (double)GetValue(RenderingModeProperty);
            set => SetValue(RenderingModeProperty, value);
        }

        public static readonly DependencyProperty RenderingModeProperty =
            DependencyProperty.Register(nameof(RenderingMode), typeof(double), typeof(NeoCard),
                new UIPropertyMetadata(1.0, (d, e) =>
                {
                    UpdateShaderPropSafe(d, shader => shader.RenderingMode = (double)e.NewValue);
                })
            );

        #endregion

        public NeoCard()
        {
            IsTabStop = false;
            Focusable = false;
            FocusVisualStyle = null;
        }

        private Border _effBorder;
        private NeoShader _shader;

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _effBorder = Template.FindName("PART_GridBorder", this) as Border;
            if (_effBorder == null) return;

            _shader = new NeoShader();
            _effBorder.Effect = _shader;

            ApplyShaderProperties();
        }

        private void ApplyShaderProperties()
        {
            _shader.OffsetX = this.OffsetX;
            _shader.OffsetY = this.OffsetY;
            _shader.BlurRadius = this.BlurRadius;
            _shader.SpreadRadius = this.SpreadRadius;
            _shader.BorderRadius = this.BorderRadius;
            _shader.PrimaryColor = this.PrimaryColor;
            _shader.SecondaryColor = this.SecondaryColor;
            _shader.Inset = this.Inset;
            _shader.RenderingMode = this.RenderingMode;
        }
    }
}